package pl.umk.mat.fred.unicore.urc.storagemanagement;

import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.unigrids.services.atomic.types.GridFileType;

import de.fzj.unicore.rcp.identity.IdentityActivator;
import de.fzj.unicore.rcp.servicebrowser.ServiceBrowserActivator;
import de.fzj.unicore.rcp.servicebrowser.nodes.Node;
import de.fzj.unicore.rcp.servicebrowser.nodes.RegistryNode;
import de.fzj.unicore.rcp.servicebrowser.nodes.StorageNode;
import de.fzj.unicore.rcp.servicebrowser.nodes.TargetSystemFactoryNode;
import de.fzj.unicore.rcp.servicebrowser.nodes.TargetSystemNode;
import de.fzj.unicore.uas.client.GridFileFilter;
import de.fzj.unicore.uas.client.IGridFileFilter;
import de.fzj.unicore.wsrflite.xmlbeans.BaseFault;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pl.umk.mat.fred.unicore.urc.storagemanagement.analytics.TimeMeter;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.GridNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.RootNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.unicore.Registry;
import pl.umk.mat.fred.unicore.urc.storagemanagement.unicore.Storage;
import pl.umk.mat.fred.unicore.urc.storagemanagement.views.StorageBrowserView;
import pl.umk.mat.fred.unicore.urc.storagemanagement.views.TimeMeterView;

/**
 * The activator class controls the plug-in life cycle
 */
public class StorageManagementActivator extends AbstractUIPlugin {

	// The plug-in ID
	public static final String PLUGIN_ID = "pl.umk.mat.fred.unicore.urc.storagemanagement";


	// The shared instance
	private static StorageManagementActivator plugin;
	
	private StorageBrowserView storageView;
	private TimeMeterView timeMeterView;
	private List<Registry> registryList;
	private List<Storage> storageList;
	private RootNode rootNode = null;
	private Cache cache;
	private Thread timeMeterThread;
	private TimeMeter timeMeter;
	private Map<String, List<Integer>> speedMap = new HashMap<String, List<Integer>>();

	/**
	 * The constructor
	 */
	public StorageManagementActivator() {
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		
		plugin = this;
		IdentityActivator.getDefault().init();
		cache = new Cache();
		speedMap = new HashMap<String, List<Integer>>();
		Job initialJob = new Job("Initialization") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				monitor.beginTask("Initialization", 0);
				for (Node n : ServiceBrowserActivator.getDefault().getGridNode().getChildren()) {
					  
					
					if (n instanceof RegistryNode) {
						List<Node> nodeList = new ArrayList<Node>();
						Registry registry = null;
						synchronized (n) {
							RegistryNode registryNode = (RegistryNode) n;
							try {
								registry = new Registry(registryNode.getEpr().getAddress().getStringValue(), storageList);
								getRegistryList().add(registry);
							} catch (Exception e1) {
								e1.printStackTrace();
								continue;
							}
							nodeList = new ArrayList<Node>(registryNode.getChildren());
						}
						for (Node n2 : nodeList) {
							synchronized (n2) {
								if (n2 instanceof TargetSystemFactoryNode) {
									TargetSystemFactoryNode tsfn = (TargetSystemFactoryNode) n2;
									for (Node n3 : tsfn.getChildren()) {
										if (n3 instanceof TargetSystemNode) {
											TargetSystemNode tsn = (TargetSystemNode) n3;
											tsn.addPropertyChangeListener(new PropertyChangeListener() {
												@Override
												public void propertyChange(PropertyChangeEvent arg0) {
													
												}
											});
											for (Node n4 : tsn.getChildren()) {
												if (n4 instanceof de.fzj.unicore.rcp.servicebrowser.nodes.StorageNode) {
													de.fzj.unicore.rcp.servicebrowser.nodes.StorageNode sn = (de.fzj.unicore.rcp.servicebrowser.nodes.StorageNode) n4;
												}
											}
										}
									}
								} else if (n2 instanceof StorageNode) {
									StorageNode sn = (StorageNode) n2;
									Storage storage = null;
									try {
										storage = new Storage(sn.getEpr().getAddress().getStringValue(), registry);
									} catch (Exception e) {
										e.printStackTrace();
									}
									if (storage != null) {
										/*
										IGridFileFilter fileFilter = new GridFileFilter("fr*");
										try {
											GridFileType[] result = storage.getClient().find("/", true, "fred", false, null, null);
	                    System.out.println("Fred storage: " + storage.getUrl());
	                    for (GridFileType gft : result) {
	                    	System.out.println(gft.getPath());
	                    }
                    } catch (BaseFault e) {
	                    // TODO Auto-generated catch block
	                    e.printStackTrace();
                    }
                    */
										getStorageList().add(storage);
										registry.getStorageList().add(storage);
										if (storageView != null) {
											storageView.addStorage(storage, true);
										}
										if (timeMeterView != null) {
											timeMeterView.addStorage(storage);
										}
									}
								}
							}
						}
					}
				}
				if (timeMeterView != null) {
					System.out.println("Refresh input");
					PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
						@Override
						public void run() {
							timeMeterView.refreshInput();
						}
					});
				}
				return Status.OK_STATUS;
			}
		};
		initialJob.schedule();
		
		timeMeter = new TimeMeter(getStorageList(), speedMap, timeMeterView);
		timeMeterThread = new Thread(timeMeter);
		
		PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
			@Override
			public void run() {
				System.out.println("Remove extension " + removeExtension("de.fzj.unicore.rcp.gpe4eclipse.extensions.StageInTypeU6Extension"));
				System.out.println("Remove extension " + removeExtension("de.fzj.unicore.rcp.gpe4eclipse.extensions.StageOutTypeU6Extension"));
			}
		});
		System.out.println("StorageManagement started");
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		for (Storage s : storageList) {
			if (s.getClient() != null) {
				s.getClient().destroy();
			}
		}
		for (Registry r : registryList) {
			if (r.getClient() != null) {
				r.getClient().destroy();
			}
		}
		if ((timeMeterThread != null) && (timeMeterThread.isAlive())) {
			timeMeterThread.interrupt();
		}
		plugin = null;
		super.stop(context);
	}

	/**
	 * Returns the shared instance
	 *
	 * @return the shared instance
	 */
	public static StorageManagementActivator getDefault() {
		return plugin;
	}

	/**
	 * Returns an image descriptor for the image file at the given
	 * plug-in relative path
	 *
	 * @param path the path
	 * @return the image descriptor
	 */
	public static ImageDescriptor getImageDescriptor(String path) {
		return imageDescriptorFromPlugin(PLUGIN_ID, path);
	}
	
	private boolean removeExtension(String extensionName) {
		ExtensionRegistry extReg = (ExtensionRegistry) Platform.getExtensionRegistry();
		
		Object token = null;
		try {
            Field field = extReg.getClass().getDeclaredField("masterToken");
            field.setAccessible(true);
            token = field.get(extReg);
        } catch (Exception e) {
        	return false;
        }
		
		IExtension ext = extReg.getExtension(extensionName);
		if (ext != null) {
			return extReg.removeExtension(ext, token);
		}
		
		return false;
	}
	
	
	public List<Registry> getRegistryList() {
		if (registryList == null) {
			registryList = Collections.synchronizedList(new ArrayList<Registry>());
		}
		return registryList;
	}

	public void setRegistryList(List<Registry> registryList) {
		this.registryList = Collections.synchronizedList(registryList);
	}

	public List<Storage> getStorageList() {
		if (storageList == null) {
			storageList = Collections.synchronizedList(new ArrayList<Storage>());
		}
		return storageList;
	}

	public void setStorageList(List<Storage> storageList) {
		this.storageList = Collections.synchronizedList(storageList);
	}
	
	public Object getObjectFromCache(String name) {
		synchronized (cache) {
			return cache.getObject(name);
		}
	}
	
	public void setObjectToCache(String name, Object object) {
		synchronized (cache) {
			cache.setObject(name, object);
		}
	}
	
	public void setTimeMeterView(TimeMeterView timeMeterView) {
		this.timeMeterView = timeMeterView;
	}
	
	public TimeMeterView getTimeMeterView() {
		return timeMeterView;
	}
	
	public Map<String, List<Integer>> getSpeedMap() {
		return speedMap;
	}
	
	public TimeMeter getTimeMeter() {
		return timeMeter;
	}

	public StorageBrowserView getStorageView() {
		return storageView;
	}

	public void setStorageView(StorageBrowserView storageView) {
		this.storageView = storageView;
	}
	
	public RootNode getRootNode() {
		if (rootNode != null) {
			return rootNode;
		}
		
		if (rootNode != null) {
			return rootNode;
		}
		rootNode = new RootNode();
		GridNode gridNode = new GridNode();
		gridNode.setParent(rootNode);
		rootNode.add(gridNode);
		//if (doubleClickAction == null) {
		//	doubleClickAction = new DoubleClickAction(treeViewer);
		//}
		for (Storage storage : StorageManagementActivator.getDefault().getStorageList()) {
			pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.StorageNode storageNode = 
					new pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.StorageNode();
			storageNode.setStorage(storage);
			storageNode.setParent(gridNode);
			gridNode.add(storageNode);
			//doubleClickAction.run(storageNode, false);
		}
		return rootNode;
	}
	
	private boolean isSleeping(Thread t) {
	    StackTraceElement[] ste = t.getStackTrace();

	    if (ste.length == 0)
	        return false;     // thread has terminated!

	    return ste[0].getClassName().equals("java.lang.Thread")
	        && ste[0].getMethodName().equals("sleep");
	}
	
	public boolean isTimeMeterWorking() {
		return timeMeter.isWorking();
	}
	
	public Thread getTimeMeterThread() {
		return timeMeterThread;
	}
	
}
